// pages/price/price.ts
import { ICategory } from "@/type/index";
import { showToast } from "@/util/index"; // 假设你有这些工具函数
import { showPrice, addPrice, updatePrice, getCategory } from "@/api/index";

const initialAddPriceForm = {
  parentId: null as string | null,
  parentName: "",
  categoryId: null as string | null,
  name: "",
  defaultUnit: "",
  categoryRemark: "",
};

Page({
  data: {
    themeColor: "#19be6b",

    // 数据存储
    allCategoriesFlat: [] as ICategory[], // 所有分类的扁平列表
    allCategoriesTree: [] as ICategory[], // 所有分类的完整树
    pricedCategoryIds: new Set<string>(), // 存储已定价分类ID的集合，用于快速查找
    treeData: [] as ICategory[], // 最终在页面上渲染的、已定价的分类树

    // 编辑弹窗状态
    showEditPopup: false,
    currentEditingItem: {} as ICategory,

    // 新增弹窗状态
    showAddPricePopup: false,
    addPriceForm: { ...initialAddPriceForm },

    // 通用表单字段 (新增和编辑共用)
    unitPrice: "", // 统一使用字符串，方便输入框绑定 (单位: 元)
    priceRemark: "",

    // 选择器相关状态
    showPicker: false,
    pickerType: "parent" as "parent" | "child",
    pickerTitle: "",
    pickerOptions: [] as any[],

    isSaving: false,
  },

  onLoad() {
    this.fetchData();
  },
  /**
   * 空操作函数，用于阻止事件冒泡
   */
  noop() {
    // Do nothing
  },
  async fetchData() {
    if (!this.data.treeData.length) {
      this.setData({ isLoading: true });
    }
    try {
      // 并行请求所有分类和已定价信息
      const [allCategoriesRes, pricedItemsRes] = await Promise.all([
        getCategory(),
        showPrice(),
      ]);
      // 1. 处理所有分类数据
      const rawAllCategories = Object.values(allCategoriesRes) as ICategory[];
      const allCategoriesTree = this.processRawCategories(rawAllCategories);
      const allCategoriesFlat = this.flattenTree(allCategoriesTree);

      // 2. 处理已定价数据
      const { pricedItems, pricedCategoryIds } = this.processPricedItems(
        pricedItemsRes
      );

      // 3. 将价格信息合并到完整分类树中，并筛选出仅含已定价项目的树
      const pricedTree = this.buildPricedTree(allCategoriesTree, pricedItems);
      this.setData({
        allCategoriesTree,
        allCategoriesFlat,
        pricedCategoryIds,
        treeData: pricedTree,
      });
    } catch (error) {
      console.error("数据加载失败", error);
      showToast("数据加载失败，请稍后重试");
    } finally {
      this.setData({ isLoading: false });
    }
  },

  /**
   * 预处理从后端获取的原始分类数据
   * - 将对象转为数组
   * - 递归处理子节点
   * - 映射 _id -> categoryId
   */
  processRawCategories(nodes: any[], level = 1): ICategory[] {
    return nodes.map((node) => {
      const newNode: ICategory = {
        ...node,
        categoryId: node._id, // 关键映射
        _level: level,
        _expanded: false, // 默认展开第一级
      };
      if (node.children && node.children.length > 0) {
        newNode.children = this.processRawCategories(node.children, level + 1);
      }
      return newNode;
    });
  },

  /**
   * 预处理已定价的商品信息
   * - 将对象转为数组
   * - 价格从 "分" 转为 "元"
   * - 提取 categoryId 到一个 Set 中，方便快速判断
   */
  processPricedItems(
    pricedRes: any
  ): { pricedItems: Map<string, ICategory>; pricedCategoryIds: Set<string> } {
    const pricedItemsRaw = Object.values(pricedRes) as any[];
    const pricedItems = new Map<string, ICategory>();
    const pricedCategoryIds = new Set<string>();

    pricedItemsRaw.forEach((item) => {
      if (item.categoryId && item.categoryId.length > 0) {
        const categoryInfo = item.categoryId[0];
        const categoryId = categoryInfo._id;
        pricedItems.set(categoryId, {
          ...categoryInfo,
          categoryId: categoryId,
          priceId: item._id, // 价格记录本身的ID
          unitPrice: item.unitPrice / 100, // 分 -> 元
          priceRemark: item.remark || "",
        });
        pricedCategoryIds.add(categoryId);
      }
    });
    return { pricedItems, pricedCategoryIds };
  },

  /**
   * 递归构建仅包含已定价项目的树
   * @param fullTree - 完整的分类树
   * @param pricedItemsMap - <categoryId, priceInfo> 的 Map
   */
  buildPricedTree(
    fullTree: ICategory[],
    pricedItemsMap: Map<string, ICategory>
  ): ICategory[] {
    const result: ICategory[] = [];
    fullTree.forEach((node) => {
      let children: ICategory[] = [];
      if (node.children && node.children.length > 0) {
        children = this.buildPricedTree(node.children, pricedItemsMap);
      }

      const priceInfo = pricedItemsMap.get(node.categoryId);
      // 保留节点的条件：自身有价格，或者其子孙节点有价格
      if (priceInfo || children.length > 0) {
        const newNode = { ...node, ...priceInfo }; // 合并价格信息
        newNode.children = children;
        result.push(newNode);
      }
    });
    return result;
  },

  /**
   * 将树形结构扁平化
   */
  flattenTree(nodes: ICategory[]): ICategory[] {
    let flatList: ICategory[] = [];
    nodes.forEach((node) => {
      flatList.push(node);
      if (node.children) {
        flatList = flatList.concat(this.flattenTree(node.children));
      }
    });
    return flatList;
  },

  // --- 新增价格弹窗逻辑 ---
  onShowAddPricePopup() {
    this.setData({
      showAddPricePopup: true,
      unitPrice: "", // 清空上次输入
      priceRemark: "", // 清空上次输入
    });
  },

  onShowParentPicker() {
    // 父级分类 = 完整分类树中的所有根节点
    const parentOptions = this.data.allCategoriesTree.filter((c) => c.enable);
    this.setData({
      pickerType: "parent",
      pickerTitle: "选择父级分类",
      pickerOptions: parentOptions,
      showPicker: true,
    });
  },

  onShowChildPicker() {
    if (!this.data.addPriceForm.parentId) return;
    const parent = this.data.allCategoriesFlat.find(
      (c) => c.categoryId === this.data.addPriceForm.parentId
    );
    if (!parent || !parent.children) {
      showToast("该分类下无子类");
      return;
    }
    // 子分类选项 = 未被禁用 且 未定价的
    const childOptions = parent.children.filter(
      (child) =>
        child.enable && !this.data.pricedCategoryIds.has(child.categoryId)
    );

    if (childOptions.length === 0) {
      showToast("该分类下已无可添加价格的子类");
      return;
    }

    this.setData({
      pickerType: "child",
      pickerTitle: "选择子级分类",
      pickerOptions: childOptions,
      showPicker: true,
    });
  },

  onPickerConfirm(e: WechatMiniprogram.CustomEvent) {
    const { value } = e.detail;
    if (this.data.pickerType === "parent") {
      if (this.data.addPriceForm.parentId === value.categoryId) {
        this.setData({ showPicker: false });
        return;
      }
      this.setData({
        "addPriceForm.parentId": value.categoryId,
        "addPriceForm.parentName": value.name,
        "addPriceForm.categoryId": null, // 重置子分类
        "addPriceForm.name": "",
        "addPriceForm.defaultUnit": "",
        showPicker: false,
      });
    } else {
      // child
      this.setData({
        "addPriceForm.categoryId": value.categoryId,
        "addPriceForm.name": value.name,
        "addPriceForm.defaultUnit": value.defaultUnit,
        showPicker: false,
      });
    }
  },

  onPickerCancel() {
    this.setData({ showPicker: false });
  },

  async onConfirmAddPrice() {
    const { categoryId } = this.data.addPriceForm;
    if (!categoryId) {
      showToast("请先选择一个子类");
      return;
    }
    const priceInYuan = parseFloat(this.data.unitPrice);
    if (isNaN(priceInYuan) || priceInYuan <= 0) {
      showToast("请输入有效的单价");
      return;
    }

    this.setData({ isSaving: true });

    // --- 乐观更新与回滚逻辑 ---
    const originalTreeData = JSON.parse(JSON.stringify(this.data.treeData));
    const originalPricedIds = new Set(this.data.pricedCategoryIds);
    this.onClosePopup();

    try {
      // 2. 发起API请求 (价格：元 -> 分)
      const params = {
        categoryId: categoryId,
        unitPrice: Math.round(priceInYuan * 100), // 元 -> 分，并取整
        priceRemark: this.data.priceRemark,
      };
      await addPrice(params);
      this.fetchData();
      showToast("新增成功");
      // 成功后，UI已是最新，无需操作
    } catch (err: any) {
      console.log(err);
      // 3. API请求失败，回滚UI
      showToast(err.message || "新增失败，请重试");
      this.setData({
        treeData: originalTreeData,
        pricedCategoryIds: originalPricedIds,
      });
    } finally {
      this.setData({ isSaving: false });
    }
  },

  // --- 编辑价格弹窗逻辑 ---
  onShowEditPopup(e: WechatMiniprogram.CustomEvent) {
    const item: ICategory = e.detail.item;
    this.setData({
      currentEditingItem: item,
      unitPrice: String(item.unitPrice), // number -> string
      priceRemark: item.priceRemark || "",
      showEditPopup: true,
    });
  },

  async onConfirmEdit() {
    const priceInYuan = parseFloat(this.data.unitPrice);
    if (isNaN(priceInYuan) || priceInYuan <= 0) {
      showToast("请输入有效的单价");
      return;
    }
    const { priceId, categoryId } = this.data.currentEditingItem;
    if (!priceId) {
      showToast("错误：价格ID不存在，无法修改");
      return;
    }

    this.setData({ isSaving: true });

    // --- 乐观更新与回滚逻辑 ---
    const originalTreeData = JSON.parse(JSON.stringify(this.data.treeData));

    // 1. 前端立即更新UI
    const updatedData = {
      unitPrice: priceInYuan,
      priceRemark: this.data.priceRemark,
    };
    const newTreeData = this.updateTreeNode(
      this.data.treeData,
      categoryId,
      updatedData
    );
    this.setData({ treeData: newTreeData });
    this.onClosePopup();
    showToast("修改中...");

    try {
      // 2. 发起API请求 (价格：元 -> 分)
      const params = {
        priceId: priceId,
        unitPrice: Math.round(priceInYuan * 100), // 元 -> 分
        priceRemark: this.data.priceRemark,
      };
      await updatePrice(params);
      showToast("修改成功");
      // 成功后，UI已是最新，无需操作
    } catch (err: any) {
      // 3. API请求失败，回滚UI
      showToast(err.message || "修改失败，请重试");
      this.setData({ treeData: originalTreeData });
    } finally {
      this.setData({ isSaving: false });
    }
  },

  /**
   * 递归更新树中的某个节点
   */
  updateTreeNode(
    nodes: ICategory[],
    targetId: string,
    dataToUpdate: Partial<ICategory>
  ): ICategory[] {
    return nodes.map((node) => {
      if (node.categoryId === targetId) {
        return { ...node, ...dataToUpdate };
      }
      if (node.children) {
        node.children = this.updateTreeNode(
          node.children,
          targetId,
          dataToUpdate
        );
      }
      return node;
    });
  },

  onClosePopup() {
    this.setData({
      showEditPopup: false,
      showAddPricePopup: false,
      addPriceForm: { ...initialAddPriceForm }, // 重置表单
    });
  },
});
